package org.easyspec.domain

import org.easyspec.EasySpec
import org.easyspec.Behavior
import org.easyspec.Context
import org.easyspec.*

class SpecParser {

	Specifications parseSpecifications(inputClasses) {
		def specifications = new Specifications()

		inputClasses.each { clz ->
			if (isSpecification(clz)) {
				specifications.add(extractSpecFrom(clz))
			}
		}
		return specifications
	}

	boolean isSpecification(clz) {
		return clz.isAnnotationPresent(EasySpec.class)
	}

	Specification extractSpecFrom(clz) {
		def spec = new Specification()
		spec.interest = extractInterestFrom(clz)
		spec.context = extractContextFrom(clz)
		spec.behaviors.addAll(extractBehaviors(clz))
		return spec
	}

	def extractInterestFrom(clz) {
		return clz.getAnnotation(EasySpec.class).interest()
	}

	def extractContextFrom(clz) {
		for (method in clz.methods) {
			if (method.isAnnotationPresent(Context.class)) {
				return method.getAnnotation(Context.class).value()
			}
		}
		throw new RuntimeException("$clz is an EasySpec specification, but does not have the @Context annotation.")
	}

	def extractBehaviors(clz) {
		def behaviors = new Behaviors()
		for (method in clz.methods) {
			if (method.isAnnotationPresent(Behavior.class)) {
				def implemented = method.getAnnotation(Behavior.class).implemented()
				def detail = parseBehaviorDetail(method)
				behaviors.add(new domain.Behavior(detail:detail, isImplemented:implemented))
			}
		}
		return behaviors
	}

	def parseBehaviorDetail(methodName) {
		def detail = methodName.name.replace('_', ' ')
		if (detail.startsWith('test')) {
			detail = detail.substring(4).trim()
		}
		return detail
	}
}